import axios from 'axios'

export {
  addSearchParamsPrefix,
  createUrlParams,
  requestFormDataInterceptor,
  requestFormDataTransform,
  responseTransform
} from './utils'

export const defaultOptions = {
  // 实例返回原始response
  originResponse: false,

  // 静默
  silence: false,

  // 转换表单数据
  useFormData: false,

  // 以下为axios属性
  responseType: 'json',

  headers: {
    'X-Requested-With': 'XMLHttpRequest'
  }
}

class Index {
  constructor (baseURL = '', options = {}) {
    // baseURL
    this.baseURL = baseURL

    // 业务名称
    this.serviceName = ''

    this.requestSuccessInterceptors = []
    this.requestErrorInterceptors = []

    this.responseSuccessInterceptors = []
    this.responseErrorInterceptors = []

    this.requestTransforms = []
    this.responseTransforms = []

    this.options = options

    this.defaultOptions = Object.assign({}, defaultOptions)
  }

  setBaseURL (baseURL = '') {
    this.baseURL = baseURL
  }

  setServiceName (serviceName = '') {
    this.serviceName = serviceName
  }

  setDefaultOptions (options = {}) {
    this.defaultOptions = Object.assign({}, defaultOptions, options)
  }

  /**
   * 添加事件
   * @param name
   * @param cb
   */
  on (name, cb) {
    if (!cb) return

    const map = {
      'request:success': 'requestSuccessInterceptors',
      'request:error': 'requestErrorInterceptors',
      'request:transform': 'requestTransforms',
      'response:success': 'responseSuccessInterceptors',
      'response:error': 'responseErrorInterceptors',
      'response:transform': 'responseTransforms'
    }

    const property = map[name]
    if (!property || this[property].indexOf(cb) > -1) return
    this[property].push(cb)
  }

  /**
   * 清除事件
   * @param name
   * @param cb
   */
  off (name, cb) {
    if (!cb) return

    const map = {
      'request:success': 'requestSuccessInterceptors',
      'request:error': 'requestErrorInterceptors',
      'request:transform': 'requestTransforms',
      'response:success': 'responseSuccessInterceptors',
      'response:error': 'responseErrorInterceptors',
      'response:transform': 'responseTransforms'
    }

    const property = map[name]
    if (!property) return
    const array = this[property]
    if (!cb) {
      array.length = 0
    } else {
      const index = array.indexOf(cb)
      if (index > -1) {
        array.splice(index, 1)
      }
    }
  }

  /**
   * 创建请求实例
   * @param serviceName
   * @param options
   * @returns {Index}
   */
  create (serviceName, options = {}) {
    const axiosInstance = axios.create()
    const api = new Index(null, options)
    api.setServiceName(serviceName)
    this.createInterceptors(axiosInstance, api)

    api.request = config => {
      const options = api.createOptions(config)
      return axiosInstance.request(options)
        .then(res => options.originResponse ? res : res.data)
    }

    ['get', 'delete', 'head'].forEach((method) => {
      api[method] = (url, config) => {
        const options = api.createOptions(config)
        return axiosInstance[method](url, options)
          .then(res => options.originResponse ? res : res.data)
      }
    });

    ['post', 'put', 'patch'].forEach((method) => {
      api[method] = (url, data, config) => new Promise((resolve, reject) => {
        setTimeout(() => {
          const options = api.createOptions(config)
          return axiosInstance[method](url, data, options)
            .then(res => {
              options.originResponse || data.originResponse ? resolve(res) : resolve(res.data)
            }
            )
            .catch(e => reject(e))
        })
      })
    })

    return api
  }

  /**
   * 创建拦截
   * @param axios
   * @param api
   */
  createInterceptors (axios, api) {
    axios.interceptors.request.use((config) => {
      const options = api.finalOptions
      const baseInterceptors = baseAPI.requestSuccessInterceptors
      const nowInterceptors = api.requestSuccessInterceptors

      Array.prototype.concat([], baseInterceptors, nowInterceptors)
        .forEach(fn => {
          config = fn.call(api, config, options)
        })

      return config
    }, (error) => {
      const options = api.finalOptions
      const baseInterceptors = baseAPI.requestErrorInterceptors
      const nowInterceptors = api.requestErrorInterceptors

      Array.prototype.concat([], baseInterceptors, nowInterceptors)
        .forEach(fn => fn.call(api, error, options))

      return Promise.reject(error)
    })

    axios.interceptors.response.use((response) => {
      const options = api.finalOptions
      const baseInterceptors = baseAPI.responseSuccessInterceptors
      const nowInterceptors = api.responseSuccessInterceptors

      Array.prototype.concat([], baseInterceptors, nowInterceptors)
        .forEach(fn => {
          response = fn.call(api, response, options)
        })

      return response
    }, (error) => {
      const options = api.finalOptions
      const baseInterceptors = baseAPI.responseErrorInterceptors
      const nowInterceptors = api.responseErrorInterceptors

      Array.prototype.concat([], baseInterceptors, nowInterceptors)
        .forEach(fn => fn.call(api, error, options))

      return Promise.reject(error)
    })
  }

  /**
   * 创建每次请求配置
   * @param options
   */
  createOptions (options = {}) {
    const defaultOptions = baseAPI.defaultOptions
    const baseOptions = baseAPI.options
    const nowOptions = this.options
    const baseURL = baseAPI.baseURL
    const serviceName = this.serviceName

    options = Object.assign({}, defaultOptions, baseOptions, nowOptions, options)
    options.baseURL = `${baseURL}/${serviceName}`

    // requestTransform
    const baseRequestTransforms = baseAPI.requestTransforms
    const nowRequestTransforms = this.requestTransforms
    options.transformRequest = [].concat(baseRequestTransforms, nowRequestTransforms, options.transformRequest || [])
      .map(fn => (data) => fn(data, options))

    // responseTransform
    const baseResponseTransforms = baseAPI.responseTransforms
    const nowResponseTransforms = this.responseTransforms
    options.transformResponse = [].concat(baseResponseTransforms, nowResponseTransforms, options.transformResponse || [])
      .map(fn => (data) => fn(data, options))

    this.finalOptions = options
    return options
  }
}

let baseAPI = new Index('/branch')
if (!window.$API) {
  window.$API = baseAPI
} else {
  baseAPI = window.$API
}
export default baseAPI
